#include <stdio.h>

void f(void)
{
    printf("in %s\n", __func__);
}

void g(int i)
{
    printf("in %s, i = %d\n", __func__, i);
}

void h(int i)
{
    printf("in %s, i = %d\n", __func__, i);
}

void k(int i)
{
    printf("in %s, i = %d\n", __func__, i);
}

int plus(int a, int b)
{
    return a + b;
}

int minus(int a, int b)
{
    return a - b;
}

void cal(int (*f)(int, int))
{
    printf("%d\n", (*f)(2, 3));
}

int main(int argc, char const *argv[])
{
    int i = 0;
    int a[] = {1, 5,};
    printf("%p\n", &i);
    printf("%p\n", a);

    // 函数的地址，用函数名字就嫩得到
    printf("%p\n", main);
    // 不知道应不应该这么用，不过也能得到一样的结果
    printf("%p\n", &main);

    int* p = f;
    // 可以赋值，但是会有警告
    // warning: initialization of 'int *' from \
    // incompatible pointer type 'void (*)()'
    // 得到的值也（好像）没有意义
    printf("\np = %d\n", p);
    // 正确的写法，指向函数的指针
    void (*pf)(void) = f;
    printf("\npf = %p\n\n", pf);

    // 通过指针调用函数
    f();
    (*pf)();

    printf("\n");
    void (*pg)(int) = g;
    g(20);
    (*pg)(10);

    // 应用1：
    // 当要分情况调用多个不同的函数时，指针可以减少修改时的工作量
    printf("\n");
    int temp;
    void (*fa[])(int) = {g, h, k};

    scanf("%d", &temp);
    if (temp >= 0 && temp < sizeof(fa) / sizeof(fa[0]))
    {
        (*fa[temp])(0);
    }

    // 应用2：
    // 不需要改变 cal 函数，只需传入函数就能计算
    printf("\n");
    cal(plus);
    cal(minus);
    
    return 0;
}